package me.spring.cloud.common.components.auth.common;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/** 可重复读取request */
@Slf4j
public class RereadableRequestWrapper extends HttpServletRequestWrapper {

  private static final int BUFFER_START_POSITION = 0;

  private static final int CHAR_BUFFER_LENGTH = 1024;

  /** input stream 的buffer */
  @Getter
  @Setter
  private final String body;

  /**
   * 构造器:对request进行缓冲
   *
   * @param request object.
   */
  public RereadableRequestWrapper(HttpServletRequest request) {
    super(request);

    StringBuilder stringBuilder = new StringBuilder();

    InputStream inputStream = null;
    try {
      inputStream = request.getInputStream();
    } catch (IOException e) {
      log.error("Error reading the request body…", e);
    }
    if (inputStream != null) {
      try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
        char[] charBuffer = new char[CHAR_BUFFER_LENGTH];
        int bytesRead;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
          stringBuilder.append(charBuffer, BUFFER_START_POSITION, bytesRead);
        }
      } catch (IOException e) {
        log.error("Fail to read input stream", e);
      }
    } else {
      stringBuilder = new StringBuilder("");
    }
    body = stringBuilder.toString();
  }

  @Override
  public ServletInputStream getInputStream() {
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
    return new CustomServletInputStream(byteArrayInputStream);
  }

  /** 带本地buffer的InputStream */
  private static class CustomServletInputStream extends ServletInputStream {

    /** 本地buffer */
    private ByteArrayInputStream byteArrayInputStream;

    /** @param byteArrayInputStream {@link ByteArrayInputStream} object. */
    CustomServletInputStream(ByteArrayInputStream byteArrayInputStream) {
      this.byteArrayInputStream = byteArrayInputStream;
    }

    @Override
    public int read() {
      return byteArrayInputStream.read();
    }

    @Override
    public boolean isFinished() {
      return false;
    }

    @Override
    public boolean isReady() {
      return false;
    }

    @Override
    public void setReadListener(ReadListener readListener) {
    }
  }
}